
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>消息重试机制与配置 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>消息重试机制与配置 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">在RocketMQ中，消费者端触发消息重试主要有哪三种情况？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">1. 消费者的MessageListener实现返回`ConsumeConcurrentlyStatus.RECONSUME_LATER`状态，这是主动要求重试。 2. 消费者处理消息过程中抛出未捕获的异常，消费线程会自动将状态设为重试。 3. 消费线程执行时间超过设定的`consumeTimeout`值（默认为15分钟）。</div>
          </div>
          <div class="card-source">来源: RocketMQ消息重试的触发条件</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">配置</div>
          <div class="card-question">RocketMQ中普通消息和顺序消息的默认重试次数有何不同？如果普通消息超过最大重试次数会发生什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">配置</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">普通消息默认重试16次。顺序消息为了保证顺序性，会无限重试，直到消费成功。对于普通消息，如果超过最大重试次数，消息会进入死信队列。</div>
          </div>
          <div class="card-source">来源: 重试次数配置</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">RocketMQ的默认重试间隔策略是怎样的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">RocketMQ采用退避策略，即重试间隔会随着重试次数的增加而逐渐延长。默认的间隔时间序列为: 10s, 30s, 1m, 2m, 3m, 4m, 5m, 6m, 7m, 8m, 9m, 10m, 20m, 30m, 1h, 2h。</div>
          </div>
          <div class="card-source">来源: 重试间隔配置</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">RocketMQ在集群消费、广播消费和顺序消费三种模式下的重试策略有何关键区别？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">1. **集群消费模式**：支持完整的重试机制。 2. **广播消费模式**：默认不支持重试，需要消费者自行实现重试逻辑。 3. **顺序消费模式**：为了保证消息的顺序，会无限重试直到消费成功，没有最大重试次数限制。</div>
          </div>
          <div class="card-source">来源: 不同消费模式的重试策略</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">什么是RocketMQ的重试队列？它的命名规则和作用是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">重试队列是用于暂存消费失败需要重试的消息的特殊Topic。每个消费组都有自己专属的重试队列，其命名格式为 `%RETRY%+消费组名`。它的主要作用是按照重试时间顺序管理待重试消息，并实现不同重试间隔的延迟投递。</div>
          </div>
          <div class="card-source">来源: 重试队列的基本概念</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">请简述一条消息在消费失败后，进入重试队列并最终被重新投递的完整流程。</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">1. 消费者消费失败，向Broker返回重试状态。 2. Broker将原始消息包装为重试消息，发送到该消费组对应的重试队列（%RETRY%+消费组名）。 3. Broker根据重试次数设置消息的延迟级别。 4. 等待特定延迟时间后，Broker将消息从重试队列中重新投递给消费者。 5. 如果再次失败，则重复上述流程；如果成功，则流程结束；如果超过最大重试次数，则消息被发送到死信队列。</div>
          </div>
          <div class="card-source">来源: 重试消息的处理流程</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">实践</div>
          <div class="card-question">为什么在使用RocketMQ重试机制时，强烈建议消费逻辑必须实现幂等性？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">实践</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">因为消息可能会因为网络问题、服务暂时不可用等原因导致消费失败并被多次重试投递。如果消费逻辑不具备幂等性，重复消费就可能导致数据错乱或业务逻辑错误，例如重复扣款、重复创建订单等。</div>
          </div>
          <div class="card-source">来源: 重试机制的最佳实践</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">在消费逻辑代码中，如何判断一条消息是否是重试消息并获取其当前的重试次数？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">可以通过调用 `MessageExt` 对象的 `getReconsumeTimes()` 方法来获取消息已经被重试的次数。通过检查这个方法的返回值，可以识别重试消息并根据重试次数执行不同的处理逻辑。</div>
          </div>
          <div class="card-source">来源: 重试消息的特殊处理</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">实践</div>
          <div class="card-question">根据文档中的最佳实践，对于临时性故障和致命性错误，应该如何合理设置重试次数？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">实践</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">对于临时性故障（如依赖服务暂时不可用），可以设置较多的重试次数，以期望服务恢复后能消费成功。对于致命性错误（如业务逻辑错误、数据格式错误），应设置较少的重试次数，使其能快速进入死信队列，以便进行人工排查和干预，避免无效重试占用系统资源。</div>
          </div>
          <div class="card-source">来源: 重试机制的最佳实践</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
